#include "Context.h"
#include "Expression.h"
#include "Functor.h"
#include "Null.h"

Definition::Definition(const std::string& _name, const AutoPointer<TreeExpression::Expression>& _data) : name(_name), data(_data) { }

std::string Definition::getName() const { return name; }

AutoPointer<TreeExpression::Expression> Definition::getData() const { return data; }

void Definition::setData(const AutoPointer<TreeExpression::Expression>& _data) { data = _data; }

Context::Context(const std::string& _name) : base(0), name(_name) { }

Context::Context(Context* _base, const std::string& _name) : base(_base), name(_name) { }

Context::~Context() { }

AutoPointer<TreeExpression::Expression> Context::searchValueDefinitionInContext(const std::string& _name) const {
	std::list< Definition >::const_iterator i;
	for (i = listDefinition.begin(); i != listDefinition.end(); ++i) {
		if (i->getName() == _name) return AutoPointer<TreeExpression::Expression>(i->getData()->cloneTree());
	}
	return AutoPointer<TreeExpression::Expression>();
}

AutoPointer<TreeExpression::Expression>  Context::searchValueDefinitionInGlobal(const std::string& _name) const {
	std::list< Definition >::const_iterator i;
	for (i = listDefinition.begin(); i != listDefinition.end(); ++i) {
		if (i->getName() == _name) return AutoPointer<TreeExpression::Expression>(i->getData()->cloneTree());//Clone the result and return
	}
	if (base == 0) return AutoPointer<TreeExpression::Expression>();
	else return base->searchValueDefinitionInGlobal(_name);
}

AutoPointer<TreeExpression::Expression> Context::searchReferenceDefinitionInContext(const std::string& _name) const {
	std::list< Definition >::const_iterator i;
	for (i = listDefinition.begin(); i != listDefinition.end(); ++i) {
		if (i->getName() == _name) return i->getData();
	}
	return AutoPointer<TreeExpression::Expression>();
}

AutoPointer<TreeExpression::Expression>  Context::searchReferenceDefinitionInGlobal(const std::string& _name) const {
	std::list< Definition >::const_iterator i;
	for (i = listDefinition.begin(); i != listDefinition.end(); ++i) {
		if (i->getName() == _name) return i->getData();
	}
	if (base == 0) return AutoPointer<TreeExpression::Expression>();
	else return base->searchReferenceDefinitionInGlobal(_name);
}

std::list < AutoPointer<TreeExpression::Expression> > Context::searchDeclarationInContext(const std::string& _name) const {
	std::list< Definition >::const_iterator i;
	std::list < AutoPointer<TreeExpression::Expression> > ris;
	for (i = listDeclaration.begin(); i != listDeclaration.end(); ++i) {
		if (i->getName() == _name) ris.push_back(AutoPointer<TreeExpression::Expression>(i->getData()->cloneTree()));
	}
	return ris;
}

std::list < AutoPointer<TreeExpression::Expression> > Context::searchDeclarationInGlobal(const std::string& _name) const {
	std::list< Definition >::const_iterator i;
	std::list < AutoPointer<TreeExpression::Expression> > ris;
	for (i = listDeclaration.begin(); i != listDeclaration.end(); ++i) {
		if (i->getName() == _name) ris.push_back(AutoPointer<TreeExpression::Expression>(i->getData()->cloneTree()));
	}
	if (base == 0) return ris;
	else return base->searchDeclarationInGlobal(_name, ris);
}

std::list< AutoPointer<TreeExpression::Expression> > Context::searchDeclarationInGlobal(const std::string& _name, std::list< AutoPointer<TreeExpression::Expression> >& ris) const {
	std::list< Definition >::const_iterator i;
	for (i = listDeclaration.begin(); i != listDeclaration.end(); ++i) {
		if (i->getName() == _name) ris.push_back(AutoPointer<TreeExpression::Expression>(i->getData()->cloneTree()));//TODO error!
	}
	if (base == 0) return ris;
	else return base->searchDeclarationInGlobal(_name, ris);
}

void Context::addDefinition(const std::string& _name, const AutoPointer<TreeExpression::Expression>& definition) {
	std::list< Definition >::iterator i;
	for (i = listDefinition.begin(); i != listDefinition.end(); ++i) {
		if (i->getName() == _name) {
			i->setData(definition);
			return;
		}
	}
	if (base != 0 && !base->_addDefinition(_name, definition)) {
		Definition pls(_name, definition);
		listDefinition.push_back(pls);
	}
}

bool Context::_addDefinition(const std::string& _name, const AutoPointer<TreeExpression::Expression>& definition) {
	std::list< Definition >::iterator i;
	for (i = listDefinition.begin(); i != listDefinition.end(); ++i) {
		if (i->getName() == _name) {
			i->setData(definition);
			return true;
		}
	}
	if (base != 0) return base->_addDefinition(_name, definition);
	return false;
}

void Context::addDefinitionInContext(const std::string& _name, const AutoPointer<TreeExpression::Expression>& definition) {
	std::list< Definition >::iterator i;
	for (i = listDefinition.begin(); i != listDefinition.end(); ++i) {
		if (i->getName() == _name) {
			i->setData(definition);
			return;
		}
	}
	Definition pls(_name, definition);
	listDefinition.push_back(pls);
}

void Context::addDeclaration(const std::string& _name, const AutoPointer<TreeExpression::Expression>& declaration) {
	std::list< Definition >::iterator i;
	for (i = listDeclaration.begin(); i != listDeclaration.end(); ++i) {
		if (i->getName() == _name) {
			TreeExpression::Functor* newfunctor = dynamic_cast<TreeExpression::Functor*>(declaration.get());
			TreeExpression::Functor* oldfunctor = dynamic_cast<TreeExpression::Functor*>(i->getData().get());
			if (newfunctor->equal(oldfunctor)) {
				i->setData(declaration);
				return;
			}
		}
	}
	Definition pls(_name, declaration);
	listDeclaration.push_back(pls);
}

Context Context::join(const Context& toJoin) const {
	std::list< Definition > declaration = listDeclaration;
	declaration.insert(declaration.end(), toJoin.listDeclaration.begin(), toJoin.listDeclaration.end());
	std::list< Definition > definition = listDefinition;
	definition.insert(definition.end(), toJoin.listDefinition.begin(), toJoin.listDefinition.end());
	Context ris(name);
	ris.listDeclaration = declaration;
	ris.listDefinition = definition;
	ris.base = base;
	return ris;
}

void Context::setBase(Context* _base) {
	base = _base;
}
